﻿#include "ui/native_dialogs.h"

#ifdef _ANIP_WINDOWS

#include <Windows.h>
#include <commdlg.h>
#include <ShlObj.h>

static const int PathBufferLength = 2048;

using namespace anip;
using namespace anip::ui;

native::DialogButton native::messageBox(
	const wstring& msg, 
	MessageType type, 
	DialogButtonSet buttons, 
	const wstring& title)
{
	UINT boxtype = MB_APPLMODAL;
	switch (type)
	{
	case MessageType::Info:
		boxtype |= MB_ICONINFORMATION; break;
	case MessageType::Warning:
		boxtype |= MB_ICONWARNING; break;
	case MessageType::Error:
		boxtype |= MB_ICONERROR; break;
	case MessageType::Question:
		boxtype |= MB_ICONQUESTION; break;
	}
	switch (buttons)
	{
	case DialogButtonSet::Ok:
		boxtype |= MB_OK; break;
	case DialogButtonSet::OkCancel:
		boxtype |= MB_OKCANCEL; break;
	case DialogButtonSet::YesNo:
		boxtype |= MB_YESNO; break;
	case DialogButtonSet::AbortRetryIgnore:
		boxtype |= MB_ABORTRETRYIGNORE; break;
	}

	HWND window = ::GetActiveWindow();
	int result = ::MessageBoxW(window, msg.c_str(), title.c_str(), boxtype);

	switch (result)
	{
	case IDOK:
		return DialogButton::Ok;
	case IDCANCEL:
		return DialogButton::Cancel;
	case IDABORT:
		return DialogButton::Abort;
	case IDRETRY:
		return DialogButton::Retry;
	case IDIGNORE:
		return DialogButton::Ignore;
	case IDYES:
		return DialogButton::Yes;
	case IDNO:
		return DialogButton::No;
	default:
		return DialogButton::Unknown;
	}
}

static int CALLBACK browseCallbackProc(HWND hWnd, UINT Msg, LPARAM lParam, LPARAM lpData) {
	/*if (Msg == BFFM_INITIALIZED) {
		SendMessageW(hWnd, BFFM_SETEXPANDED, 1, lParam);
	}*/
	return 0;
}

wstring native::directorySelectionDialog(const wstring& path)
{
	BROWSEINFOW bInfo;
	ZeroMemory(&bInfo, sizeof(bInfo));
	bInfo.hwndOwner = GetActiveWindow();
	bInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
	bInfo.lpfn = browseCallbackProc;

	if (!path.empty())
	{
		wchar_t initialDir[PathBufferLength] = L"";
		GetFullPathNameW(path.c_str(), PathBufferLength, initialDir, nullptr);
		bInfo.lParam = (LPARAM)initialDir;
	}

	PIDLIST_ABSOLUTE lpItem = SHBrowseForFolderW(&bInfo);
	if (!lpItem) return L"";

	wchar_t szDir[PathBufferLength] = L"";
	SHGetPathFromIDListW(lpItem, szDir);
	return szDir;
}

static wstring fileDialog(
	bool open, 
	const wstring& path, 
	const wstring& defaultName,
	const std::list<native::FileFilterItem>& filter, 
	int defaultFilter, 
	const wstring& defaultExt)
{
	OPENFILENAMEW ofn;
	ZeroMemory(&ofn, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = GetActiveWindow();
	ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST
		| OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
	ofn.lpstrDefExt = defaultExt.c_str();

	wchar_t file[PathBufferLength] = L"";
	swprintf_s(file, L"%s", defaultName.c_str());
	ofn.lpstrFile = file;
	ofn.nMaxFile = PathBufferLength;

	wstring filterNew;
	for (auto& i : filter)
		filterNew += i.description + L"\0" + i.filter + L"\0";
	ofn.lpstrFilter = filterNew.c_str();

	if (defaultFilter >= 0)
	{
		assert((unsigned int)defaultFilter < filter.size());
		ofn.nFilterIndex = defaultFilter + 1;
	}

	BOOL success = open ? GetOpenFileNameW(&ofn) : GetSaveFileNameW(&ofn);
	if (!success) return L"";
	return file;
}

wstring native::openFileDialog(
	const wstring& path, 
	const wstring& defaultName, 
	const std::list<FileFilterItem>& filter,
	int defaultFilter)
{
	return fileDialog(true, path, defaultName, filter, defaultFilter, L"");
}

wstring native::saveFileDialog(
	const wstring& path, 
	const wstring& defaultName,
	const std::list<FileFilterItem>& filter,
	int defaultFilter, 
	const wstring& defaultExt)
{
	return fileDialog(false, path, defaultName, filter, defaultFilter, defaultExt);
}

#endif